﻿using System;
using System.Reflection;

namespace WSKnowledge.WSHelpers.NHibernate
{
	public abstract class EntityBase<TEntity> : IEntity<TEntity>
	{
		private long _id;
		public virtual long Id
		{
			get { return _id; }
			protected set { _id = value;}
		}

		private int _version;
		public virtual int Version
		{
			get { return _version; }
			protected set { _version = value; }
		}

		protected EntityBase() { }

		public abstract bool Equals(TEntity entity);

		public override bool Equals(object obj)
		{
			var other = obj as EntityBase<TEntity>;
			if (other == null) return false;

			// handle the case of comparing two NEW objects
			bool thisIsTransient = (Id == 0);
			bool otherIsTransient = (other.Id == 0);

			if (otherIsTransient && thisIsTransient)
				return ReferenceEquals(this, other);

			return Id.Equals(other.Id);
		}

		/// <summary>
		/// Implementation for Andrew Arnott (JMPInline)
		/// http://blog.nerdbank.net/2006/01/why-equals-and-gethashcode-are-so.html
		/// 
		/// Note: this implementation doesn't preserve the hash code generated when it was transiet.
		/// </summary>
		/// <returns></returns>
		public override int GetHashCode()
		{
			if (Id == 0) return base.GetHashCode();

			var stringRepresentation
				= MethodBase.GetCurrentMethod().DeclaringType.FullName + "#" + Id;

			return stringRepresentation.GetHashCode();
		}

		public static bool operator ==(EntityBase<TEntity> x, EntityBase<TEntity> y)
		{
			return Equals(x, y);
		}

		public static bool operator !=(EntityBase<TEntity> x, EntityBase<TEntity> y)
		{
			return !(x == y);
		}

		public override string ToString()
		{
			return String.Format("{0}::#{1}", typeof(TEntity).Name, Id);
		}

		public abstract bool Validate();
	}
}
